﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;

namespace SpeakupBackend.Themes
{
    public abstract class BaseLevelGroupFactory<LevelGroupType> : ILevelGroupFactory<LevelGroupType>
        where LevelGroupType : LevelGroup 
    {
        List<KeyValuePair<int, int>> m_validLevelGroups;
        public IList<KeyValuePair<int, int>> ValidLevelGroups
        {
            get
            {
                return m_validLevelGroups;
            }
        }

        List<LevelGroupType> m_availableLevelGroups;
        List<LevelGroupType> AvailableLevelGroups
        {
            get
            {
                if (m_availableLevelGroups == null)
                {
                    m_availableLevelGroups = new List<LevelGroupType>();
                    foreach (var tuple in ValidLevelGroups)
                    {
                        m_availableLevelGroups.Add( CreateLevelGroup(tuple.Key, tuple.Value) );
                    }
                }

                return m_availableLevelGroups;
            }
        }

        Dictionary<Level, LevelGroupType> m_level2LevelGroup;
        Dictionary<Level, LevelGroupType> Level2LevelGroup
        {
            get
            {
                if (m_level2LevelGroup == null)
                {
                    m_level2LevelGroup = new Dictionary<Level, LevelGroupType>();
                    foreach (LevelGroupType lg in AvailableLevelGroups)
                    {
                        for (int i = lg.MinLevel; i <= lg.MaxLevel; i++)
                        {
                            m_level2LevelGroup.Add(Level.GetLevel(i), lg);
                        }
                    }
                }

                return m_level2LevelGroup;
            }
        }

        protected BaseLevelGroupFactory(IList<KeyValuePair<int, int>> validLevelGroups)
        {
            if (validLevelGroups == null)
            {
                throw new ArgumentException("validLevelGroups");
            }
            m_validLevelGroups = validLevelGroups.ToList();
        }       


        public bool IsValidLevelGroup(int minLevelNumber, int maxLevelNumber)
        {
            foreach (var curItem in m_validLevelGroups)
            {
                if (curItem.Key == minLevelNumber && curItem.Value == maxLevelNumber)
                    return true;
            }

            return false;
        }

        public LevelGroupType GetLevelGroup(int level)
        {
            return GetLevelGroup(Level.GetLevel(level));
        }

        public LevelGroupType GetLevelGroup(Level level)
        {
            return Level2LevelGroup[level];
        }

        public LevelGroupType GetLevelGroup(int minLevelNumber, int maxLevelNumber)
        {
            var foundItems = AvailableLevelGroups.Find(x => 
                                              x.MinLevel == minLevelNumber && 
                                              x.MaxLevel == maxLevelNumber);  
          
            if(foundItems == null)
            {
                throw new ArgumentException("min/max levels");
            }
            return foundItems;
        }

        public LevelGroupType GetLevelGroup(String strLevelGroup)
        {
            //valid formats: X or X-Y

            string[] strLevels = strLevelGroup.Split(new char[] { LevelGroup.LevelSplitter });
            if (strLevels.Length < 1 || strLevels.Length > 2)
            {
                throw new FormatException(String.Format("Invalid LevelGroup - \"{0}\"", strLevelGroup));
            }

            int[] levels = new int[strLevels.Length];
            for (int i = 0; i < strLevels.Length; i++)
            {
                if (!Int32.TryParse(strLevels[i], NumberStyles.Integer, CultureInfo.InvariantCulture, out levels[i]))
                {
                    throw new FormatException(String.Format("Can't parse {0} in {1}", strLevels[i], strLevelGroup));
                }
            }

            int minLevel = levels[0];
            int maxLevel = levels[levels.Length - 1];
            return GetLevelGroup(minLevel, maxLevel);
        }

        public IList<LevelGroupType> GetLevelGroups()
        {
            return AvailableLevelGroups.AsReadOnly();
        }

        protected abstract LevelGroupType CreateLevelGroup(int min, int max);        
    }
}
